#include "normalscreen.h"
#include <QMouseEvent>
#include <QDebug>
extern "C" {
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
}

NormalScreen::NormalScreen(QWidget *parent)
    : NormalScreen(0, parent)
{

}

NormalScreen::NormalScreen(int id, QWidget *parent)
    : QLabel(parent)
    , m_screenWidth(640), m_screenHeight(360)
    , oldx(0), oldy(0)
    , m_c(nullptr)
    , m_timeout(false)
    , m_timer(this)
{
    this->m_id = id;
    this->setScaledContents(true);
    this->setMouseTracking(true);
    this->m_timer.start(40);
    connect(&m_timer, &QTimer::timeout, this, &NormalScreen::on_timeout);
}

int NormalScreen::getId()
{
    return this->m_id;
}

void NormalScreen::mousePressEvent(QMouseEvent *event)
{
    QPointF cur_pos = event->localPos();
    emit mouseChanged(event->button(), true, convertToReal(cur_pos));
    oldx = event->localPos().x();
    oldy = event->localPos().y();
}

void NormalScreen::mouseMoveEvent(QMouseEvent* event)
{
    if(!m_timeout)
    {
        return;
    }
    QPointF cur_pos = event->localPos();
    if(fabs(cur_pos.x() - oldx)>0.01 || fabs(cur_pos.y() - oldy)>0.01)
    {
        oldx = cur_pos.x();
        oldy = cur_pos.y();
        emit mouseChanged(Qt::MouseButton::NoButton, true, convertToReal(cur_pos));
    }
    m_timeout = false;
}

void NormalScreen::mouseReleaseEvent(QMouseEvent *event)
{
    QPointF cur_pos = event->localPos();
    emit mouseChanged(event->button(), false, convertToReal(cur_pos));
    oldx = event->localPos().x();
    oldy = event->localPos().y();
}

void NormalScreen::wheelEvent(QWheelEvent *event)
{
    emit wheelChanged(event->delta());
}

QPoint NormalScreen::convertToReal(const QPointF &inPoint)
{
    QPoint real;
    qreal x,y;
    if(width()==0 || height()==0)
    {
        return QPoint(0, 0);
    }
    x=inPoint.x()/width();
    y=inPoint.y()/height();
    real.setX(int(x * m_screenWidth));
    real.setY(int(y * m_screenHeight));
    return real;
}

void NormalScreen::keyPressEvent(QKeyEvent *event)
{
    emit keyChanged(event->key(), true);
}

void NormalScreen::keyReleaseEvent(QKeyEvent *event)
{
    emit keyChanged(event->key(), false);
}

void NormalScreen::setPixmap(const QPixmap &pixmap)
{
    QLabel::setPixmap(pixmap);
}

void NormalScreen::putFramebuffer(const QByteArray &data)
{
    AVPacket *pkt = av_packet_alloc();
    AVFrame *frame = av_frame_alloc();
    int ret;

    pkt->data=static_cast<uint8_t*>(static_cast<void*>(const_cast<char *>(data.data())));
    pkt->size = data.size();
    ret = avcodec_send_packet(m_c, pkt);
    if(ret<0)
    {
        qCritical()<<"Error sending a packet for decoding";
        return;
    }
    while(ret >=0)
    {
        ret = avcodec_receive_frame(m_c, frame);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during decoding\n");
            qCritical()<<"Error during decoding";
        }
        //显示图片
        sws_scale(m_sws, frame->data, frame->linesize, 0, frame->height, m_argbFrame->data, m_argbFrame->linesize);
        QImage img(reinterpret_cast<unsigned char*>(m_argbFrame->data[0]), frame->width, frame->height, QImage::Format_RGBA8888);
        setPixmap(QPixmap::fromImage(img));
    }
    av_frame_free(&frame);
    av_packet_free(&pkt);
}

void NormalScreen::setScreenSize(int width, int height, int codecId)
{
    m_screenWidth = width;
    m_screenHeight = height;
    m_codec_id = codecId;
    initCodec(width, height, codecId);
//    this->resize(width, height);
}

void NormalScreen::on_timeout()
{
    m_timeout = true;
}

void NormalScreen::initCodec(int width, int height, int codecId)
{
    // 初始化解码器
//    const AVCodec *codec = avcodec_find_decoder(AVCodecID(codecId));
    const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!codec) {
        qCritical()<<"找不到解码器";
    }
    m_c = avcodec_alloc_context3(codec);
    if (!m_c) {
        qCritical()<<"初始化解码器失败";
    }
    if(avcodec_open2(m_c, nullptr, nullptr)<0)
    {
        qCritical()<<"无法打开解码器";
    }
    this->m_sws = sws_getContext(width, height, AVPixelFormat::AV_PIX_FMT_YUV420P
                       , width, height, AVPixelFormat::AV_PIX_FMT_RGBA
                       , SWS_POINT, nullptr, nullptr, nullptr);
    m_argbFrame = av_frame_alloc();
    m_argbFrame->format = AVPixelFormat::AV_PIX_FMT_ARGB;
    m_argbFrame->width = width;
    m_argbFrame->height = height;
    av_frame_get_buffer(m_argbFrame, 0);
    qDebug()<<"解码器初始化完成";
}

void NormalScreen::freeCodec()
{
    avcodec_free_context(&m_c);
    sws_freeContext(m_sws);
    m_sws = nullptr;
    av_frame_free(&m_argbFrame);
}
